<?php

// 平台订单模型

namespace app\api\model;

use app\api\model\PaymentOtherOrder;
use app\api\model\PaymentOrderNotify;
use app\api\model\PaymentCash;
use app\api\model\PaymentUserWhitelist;
use think\Model;
use think\Db;
use think\facade\Cache;
use think\facade\Log;
use think\facade\Request;

class PaymentOrder extends Model
{

    // 数据表名称,不包括表前缀
    protected $name = 'payment_order';
    // 数据表主键
    protected $pk = 'order_id';
    // 时间字段取出后的默认时间格式
    protected $dateFormat = false;
    // Redis缓存驱动
    public $redis;

    protected function initialize()
    {
        parent::initialize();
        // redis连接缓存驱动
        $this->redis = Cache::store('redis');
        // 文件连接缓存驱动
        // $this->redis =Cache::store('file');
    }

    /**
     * 第三方通知相关操作
     * @access public
     * @param  string  $order_id         平台订单号
     * @param  string  $notify_param     通知参数
     * @param  string  $cash             金额
     * @param  string  $now_cash         实际金额
     * @param  string  $verify_param     验证参数
     * @param  string  $other_order_id   第三方订单号
     * @param  string  $payment_company  第三方总支付公司
     * @param  boolean $verify_rule      验证订单规则
     * @param  boolean $verify_sign      验证sign
     * @param  boolean $all_order_verify 内部绿色通道
     * @return mixed
     */
    public function notifyAbout($order_id = 0, $notify_param = '', $cash = 0, $now_cash = 0, $verify_param = 0, $other_order_id = 0, $payment_company = '', $verify_rule = true, $verify_sign = false, $all_order_verify = true)
    {

        // 查找订单
        $order_arr = self::where(['order_id' => $order_id])->find();
        if ($order_arr) {
            if (in_array($order_arr['company'], ['kjpay', 'sprflat'])) {
                $cash = $order_arr['cash'] / 100;
            }

            // 实例化第三方订单模型
            $payment_other_order_obj = new PaymentOtherOrder();
            $company_config = $this->redis->get($order_arr['company']);
            $child_company_config = $this->redis->get($order_arr['child_company']);
            // 合并支付公司默认商户号和子商户号配置
            $company_merge_values = array_merge($company_config['value'], $child_company_config['value']);

            // 内部绿色通道，是否关闭验证（比如模拟第三方通知）
            if ($all_order_verify) {
                // 验证第三方订单状态（总开关验证），是否开启
                $order_verify = $this->redis->get('order_verify');
                if (isset($order_verify['status']) && $order_verify['status'] == 1) {
                    if (!$company_config) {
                        abort(404, "平台订单号是（{$order_arr['order_id']}）：验证第三方订单支付状态，（{$order_arr['company']}）支付公司配置错误");
                    }
                    // 支付公司订单验证开启
                    if ($company_config['value']['company_order_verify']) {
                        // $verify_rule为true验证第三方订单，为false验证平台订单号
                        $verify_order_id = $verify_rule ? $other_order_id : $order_id;
                        $company = $order_arr['company'] . 'Verify';
                        $verify = $payment_other_order_obj->$company($verify_order_id, $company_merge_values, $order_arr);
                        if (!$verify) {
                            abort(404, "平台订单号是（{$order_arr['order_id']}）：接口查询:可能用户没有支付成功，第三方支付订单号是（{$other_order_id}），也有可能第三方支付公司（{$order_arr['company']}）做了主从数据库（延迟），导致订单查询显示未支付");
                        }
                    }
                }

                // 访问请求ip地址
                $request_ip = Request::instance()->ip();
                if ($company_merge_values['notify_ip']) {
                    if (!in_array($request_ip, $company_merge_values['notify_ip'])) {
                        abort(404, "平台订单号是（{$order_arr['order_id']}）：上游服务端通知IP（{$request_ip}）不在白名单中");
                    }
                }

                if ($verify_sign) {
                    $company = $order_arr['company'] . 'Sign';
                    $sign = $payment_other_order_obj->$company($order_id, $company_merge_values);
                    if (!$sign) {
                        abort(404, "平台订单号是（{$order_arr['order_id']}）：验证sign失败");
                    }
                }
            }

            // 订单状态：1:待支付 2:成功 3:失败 4:退款中 5:退款成功 6:退款失败 7:冻结 8:异常 9:驳回 10:关闭
            switch ($order_arr['status']) {
                    // 订单创建成功
                case '1':
                    // 默认支付订单要在30天内完成
                    if (time() > $order_arr['create_time'] + 86400 * 30) {
                        $remark = "第三方{$order_arr['company']}支付，默认支付订单要在30天内完成";
                    }
                    // 验证公司
                    if ($order_arr['company'] != $payment_company) {
                        $remark = "涉嫌修改第三方支付公司{$order_arr['company']}名称：{$payment_company}";
                    }
                    // 验证自定义参数
                    if ($order_arr['verify_param'] != $verify_param) {
                        $remark = "涉嫌修改第三方支付公司{$order_arr['company']}的验证参数verify_param：{$verify_param}";
                    }
                    // 验证金额
                    if ($order_arr['cash'] != intval(strval($cash * 100))) {
                        $remark = "涉嫌修改第三方支付公司{$order_arr['company']}的充值金额：{$cash}";
                    }
                    // 创建金额和支付金额相差
                    if ($cash - $now_cash > 20) {
                        $remark = "涉嫌修改创建金额{$cash}和支付金额{$now_cash}相差范围，第三方支付公司{$order_arr['company']}";
                    }
                    if (isset($remark)) {
                        self::where(['order_id' => $order_id, 'status' => 1])
                            ->update(['remark' => $remark, 'status' => 8, 'other_order_id' => $other_order_id, 'update_time' => time()]);
                        payment_error_log(620000, $notify_param);
                        abort(404, $remark);
                    }

                    // 第三方可能会在一秒中多次通知相同订单，用redis处理。
                    $order_notify_key = 'order_notify_' . $order_arr['order_id'];
                    $order_notify = $this->redis->has($order_notify_key);
                    if ($order_notify) {
                        $this->redis->inc($order_notify_key, 1);
                        //payment_error_log(620001, $order_arr);
                        abort(404, "{$order_arr['company']}支付，订单通知有误1，原因可能是支付公司在一秒中多次通知相同订单");
                    } else {
                        $this->redis->set($order_notify_key, 1, 5);
                    }
                    $order_notify_value = $this->redis->get($order_notify_key);
                    if (!$order_notify_value || $order_notify_value > 1) {
                        payment_error_log(620002, $order_arr);
                        abort(404, "{$order_arr['company']}支付，订单通知有误2，原因可能是支付公司在一秒中多次通知相同订单");
                    }

                    // 转换整数，比如$cash=19.99
                    $cash = intval(strval($cash * 100));
                    $now_cash = intval(strval($now_cash * 100));

                    $payment_order_data = [
                        'status' => 2,
                        'now_cash' => $now_cash,
                        'notify_param' => json_encode($notify_param, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                        'other_order_id' => $other_order_id,
                        'update_time' => time(),
                    ];
                    // 更新平台订单表状态
                    try {
                        $update_data = self::where(['order_id' => $order_id, 'status' => 1])->update($payment_order_data);
                    } catch (\Exception $e) {
                        payment_error_log(620003, $order_arr, $e->getMessage());
                        abort(404, "更新平台订单表状态失败1,{$order_arr['company']}支付");
                    }
                    // 是否更新成功
                    if ($update_data) {
                        return $this->paySuccess($order_arr, $other_order_id, $cash, $now_cash);
                    } else {
                        payment_error_log(620004, $order_arr);
                        abort(404, "更新平台订单表状态失败2,{$order_arr['company']}支付");
                    }

                    // 订单已经支付完成
                case '2':
                    //payment_error_log(620005, $order_arr, "可能是第三方用了(多台服务器通知)，也有可能是第一次支付公司（{$order_arr['company']}）通知出现异常，状态已经修改，但是没有返回success", false);
                    return 'success';
                default:
                    // 状态错误
                    abort(404, "订单支付状态错误,现在状态是（{$order_arr['status']}）");
            }
        } else {
            // 订单号不存在
        }
        abort(404, '可能是别人在模拟第三方通知，或者程序出现异常');
    }

    /**
     * 成功相关操作
     * @access public
     * @param  array   $order_arr        订单数组
     * @param  string  $other_order_id   第三方订单号
     * @param  string  $cash             金额
     * @param  string  $now_cash         实际金额
     * @return mixed
     */
    public function paySuccess($order_arr = [], $other_order_id = 0, $cash = 0, $now_cash = 0)
    {

        // 第三方可能会在一秒中多次通知相同订单，用redis处理。
        $order_notify_key = 'merchant_order_notify_' . $order_arr['order_id'];
        $order_notify = $this->redis->has($order_notify_key);
        if ($order_notify) {
            payment_error_log(620006, $order_arr);
            abort(404, "{$order_arr['company']}支付，订单通知有误3，原因可能是支付公司在一秒中多次通知相同订单");
        } else {
            $this->redis->set($order_notify_key, 1, 5);
        }

        // 此商户号全部配置
        $merchant_config = $this->redis->get($order_arr['merchant_id']);
        // 商户号配置值
        $merchant_value = $merchant_config['value'];
        // 支付公司中的子公司商户号配置
        $children_company_config = $this->redis->get($order_arr['child_company']);
        // 子公司商户号配置值
        $children_company_value = $children_company_config['value'];

        // 更新商户号钱包
        PaymentCash::addCash($order_arr, $merchant_value, $children_company_value);

        // 把支付成功信息通知给商户号
        $merchant_create_param = json_decode($order_arr['create_param'], true);
        $key = $merchant_create_param['key'];
        $notify_url = $merchant_create_param['notify_url'];
        $notify_data['code'] = 10000;                                         // 成功状态码
        $notify_data['merchant_id'] = $order_arr['merchant_id'];              // 商户号
        $notify_data['merchant_order_id'] = $order_arr['merchant_order_id'];  // 商户号订单号
        $notify_data['order_id'] = $order_arr['order_id'];                    // 平台订单号
        $notify_data['app_id'] = $merchant_create_param['app_id'];            // 应用id
        $notify_data['cash'] = $merchant_create_param['cash'];                // 充值现金
        $notify_data['type'] = $merchant_create_param['type'];                // 支付类型，支付宝或微信等等
        $notify_data['trade_type'] = $merchant_create_param['trade_type'];    // 交易类型：比如充值、提现
        $notify_data['time'] = time();                                        // 更新时间
        $notify_data['extra'] = $merchant_create_param['extra'];              // 商户号自定义备注
        // 订单状态：1:待支付 2:成功 3:失败 4:退款中 5:退款成功 6:退款失败 7:冻结 8:异常 9:驳回 10:关闭
        $notify_data['status'] = 2;
        $notify_data['sign'] = md5('merchant_id=' . $notify_data['merchant_id'] . '&merchant_order_id=' . $notify_data['merchant_order_id'] . '&order_id=' . $notify_data['order_id'] . '&cash=' . $notify_data['cash'] . '&type=' . $notify_data['type'] . '&time=' . $notify_data['time'] . '&key=' . $key);

        $resdata = go_curl($notify_url, $notify_data, 'get', 8);
        if (stripos($resdata, 'success') === false) {
            // 通知失败,准备多次通知
            $url_param = http_build_query($notify_data);
            $url = strpos($notify_url, '?') !== false ? $notify_url . '&' . $url_param : $notify_url . '?' . $url_param;

            $notify_array = [
                'order_id' => $order_arr['order_id'],
                'merchant_id' => $order_arr['merchant_id'],
                'merchant_order_id' => $order_arr['merchant_order_id'],
                'other_order_id' => $other_order_id,
                'app_id' => $order_arr['app_id'],
                'cash' => $order_arr['cash'],
                'type' => $order_arr['type'],
                'trade_type' => $order_arr['trade_type'],
                'status' => 0,
                'manual' => 0,
                'count' => 0,
                'create_time' => $order_arr['create_time'],
                'update_time' => time(),
                'url' => $url,
                'remark' => substr($resdata, 0, 60000),
            ];

            // 插入多次通知数据库
            try {
                PaymentOrderNotify::create($notify_array);
            } catch (\Exception $e) {
                payment_error_log(620007, $notify_array, $e->getMessage());
            }
            Log::record("支付通知商户号{$order_arr['merchant_id']}失败记录：" . $order_arr['order_id'] . '——' . '0', 'log');
            Log::record('支付通知URL参数：' . $url, 'log');
            Log::record('支付通知返回内容：' . $resdata, 'log');
        }

        if ($order_arr['merchant_id'] == '55555555') {

            $shop = Db::name('vpn_shop')->where(['cid' => $order_arr['shop_id']])->find();
            $user = Db::name('admin_user')->where(['id' => $order_arr['user_id']])->find();

            $user_update = [];
            $day = $shop['day'] * 86400;
            if ($shop['mode'] == 0) {
                $user['expire_time'] = $user['expire_time'] ? $user['expire_time'] : 0;
                if ($user['expire_time'] < time()) {
                    $update_time = time() + $day;
                } else {
                    $update_time =  $user['expire_time'] + $day;
                }
                $user_update['expire_time'] = $update_time;
            }

            if ($shop['mode'] == 1) {
                $user['high_expire_time'] = $user['high_expire_time'] ? $user['high_expire_time'] : 0;
                if ($user['high_expire_time'] < time()) {
                    $update_time = time() + $day;
                } else {
                    $update_time =  $user['high_expire_time'] + $day;
                }
                $user_update['high_expire_time'] = $update_time;
            }
            $user_update['update_time'] = time();
            $user_update_status = Db::name('admin_user')->where(['id' => $order_arr['user_id']])->update($user_update);
            if (!$user_update_status) {
                vpn_error_log(900001, input());
            }

            $user_info_id = 'vpn_user_info_id_' . $order_arr['user_id'];
            $this->redis->pull($user_info_id);
        }

        $expire = strtotime(date('Y-m-d', strtotime('+1 day'))) - time();

        // 更新商户号今天已经充值的金额总数
        $merchant_day_recharge_cash_sum = $order_arr['merchant_id'] . '_day_recharge_cash_sum';
        $now_merchant_day_recharge_cash_sum = $this->redis->has($merchant_day_recharge_cash_sum);
        if ($now_merchant_day_recharge_cash_sum) {
            $this->redis->inc($merchant_day_recharge_cash_sum, $cash);
        } else {
            $this->redis->set($merchant_day_recharge_cash_sum, $cash, $expire);
        }

        // 更新商户号今天已经充值的支付类型金额总数
        $merchant_day_recharge_type_cash_sum = $order_arr['merchant_id'] . '_day_recharge_type_cash_sum_' . $order_arr['type'];
        $now_merchant_day_recharge_type_cash_sum = $this->redis->has($merchant_day_recharge_type_cash_sum);
        if ($now_merchant_day_recharge_type_cash_sum) {
            $this->redis->inc($merchant_day_recharge_type_cash_sum, $cash);
        } else {
            $this->redis->set($merchant_day_recharge_type_cash_sum, $cash, $expire);
        }

        // 更新支付公司中的子商户号今天已经充值的金额总数
        $children_day_recharge_cash_sum = $order_arr['child_company'] . '_day_recharge_cash_sum';
        $now_children_day_recharge_cash_sum = $this->redis->has($children_day_recharge_cash_sum);
        if ($now_children_day_recharge_cash_sum) {
            $this->redis->inc($children_day_recharge_cash_sum, $cash);
        } else {
            $this->redis->set($children_day_recharge_cash_sum, $cash, $expire);
        }

        // 更新支付公司中的子商户号今天已经充值的支付类型金额总数
        $children_day_recharge_type_cash_sum = $order_arr['child_company'] . '_day_recharge_type_cash_sum_' . $order_arr['type'];
        $now_children_day_recharge_type_cash_sum = $this->redis->has($children_day_recharge_type_cash_sum);
        if ($now_children_day_recharge_type_cash_sum) {
            $this->redis->inc($children_day_recharge_type_cash_sum, $cash);
        } else {
            $this->redis->set($children_day_recharge_type_cash_sum, $cash, $expire);
        }

        // 清空商户号支付类型对应未支付数量
        $now_merchant_no_pay_sum_warn_type = $order_arr['merchant_id'] . '_no_pay_sum_warn_type_' . $order_arr['type'];
        $this->redis->pull($now_merchant_no_pay_sum_warn_type);

        // 删除IP灰名单
        $gray_list_ip = 'gray_list_ip_' . $merchant_create_param['ip'];
        $this->redis->pull($gray_list_ip);

        // 通道每天最多支付成功次数
        $children_company_success_count = $order_arr['child_company'] . '_success_count';
        $now_children_company_success_count = $this->redis->has($children_company_success_count);
        if ($now_children_company_success_count) {
            $this->redis->inc($children_company_success_count, 1);
        } else {
            $this->redis->set($children_company_success_count, 1, $expire);
        }

        // 商户是否开启支付公司轮循（顺序轮循）
        if ($merchant_value['pay_polling_open'][$order_arr['type']] == 2) {
            // 支付公司轮循开关
            $pay_polling_open = $this->redis->get('pay_polling_open');
            if ($pay_polling_open && $pay_polling_open['status'] == 1) {
                $merchant_id_pay_company_array = [$order_arr['child_company']];
                $merchant_id_pay_company = $order_arr['merchant_id'] . '_pay_company';
                $now_merchant_id_pay_company = $this->redis->get($merchant_id_pay_company);
                if ($now_merchant_id_pay_company) {
                    $now_merchant_id_pay_company_array_diff = array_diff($now_merchant_id_pay_company, $merchant_id_pay_company_array);
                    $now_merchant_id_pay_company_config = array_merge($now_merchant_id_pay_company_array_diff, $merchant_id_pay_company_array);
                    $this->redis->set($merchant_id_pay_company, $now_merchant_id_pay_company_config, $expire);
                } else {
                    $this->redis->set($merchant_id_pay_company, $merchant_id_pay_company_array, $expire);
                }
            }
        }

        // 处理vip用户数据
        if ($order_arr['user_id']) {
            // 删除未支付vip用户 
            $children_company_user = $order_arr['child_company'] . $order_arr['user_id'];
            $this->redis->pull($children_company_user);

            if ($merchant_value['vip_user_open'] == 1) {

                $all_good_company = $this->redis->get('all_good_company');
                if ($all_good_company && $all_good_company['status'] == 1) {
                    // 用户白名单
                    $user_whitelist = PaymentUserWhitelist::where('merchant_id', $order_arr['merchant_id'])
                        ->where('user_id', $order_arr['user_id'])
                        ->where('app_id', $order_arr['app_id'])
                        ->find();
                    if ($user_whitelist && $user_whitelist['status'] == 1) {

                        if (in_array($order_arr['child_company'], array_keys($all_good_company['value']))) {

                            if ($children_company_value['vip_user_success'] != '0') {

                                // 优质支付通道对应的vip用户每天最多支付成功次数
                                $children_company_user_success = $order_arr['child_company'] . $order_arr['merchant_id'] . $order_arr['user_id'];
                                $now_children_company_user_success = $this->redis->get($children_company_user_success);
                                if ($now_children_company_user_success) {
                                    $this->redis->inc($children_company_user_success, 1);
                                } else {
                                    $this->redis->set($children_company_user_success, 1, $expire);
                                }
                            }
                        }
                    }
                }
            }
        }


        // 处理完数据，给第三方支付返回接收成功
        return 'success';
    }
}
